﻿using Sidvall.Business;
using Sidvall.Collections;
using Sidvall.Data;
using Sidvall.Serialization;
using System.Collections.Generic;
using System.Linq;

namespace Sidvall.UI.Entities
{
    public static class TreeManager
    {
        #region Public Members

        public const string DefaultNameSeparator = "\\";

        #region CreateTree

        public static TreeItemCollection CreateTree(string parentId, params IItem[] value)
        {
            return CreateTree(parentId, value.AsEnumerable());
        }
        public static TreeItemCollection CreateTree(string parentId, IEnumerable<IItem> value)
        {
            var items = new TreeItemCollection();
            items.AddItems(value, parentId);
            return items;
        }
        public static TreeItemCollection CreateTree(params IParentItem[] value)
        {
            return CreateTree(value.AsEnumerable());
        }
        public static TreeItemCollection CreateTree(IEnumerable<IParentItem> value)
        {
            var items = new TreeItemCollection();
            if (value != null)
            {
                using (var manager = new BusinessCollectionSettingsManager(items, BusinessCollectionSettings.CreateSettingsNone()))
                {
                    ProcessParent(value, items, string.Empty);
                }
            }
            return items;
        }
        public static TreeItemCollection CreateTree(params IChildItem[] value)
        {
            return CreateTree(value.AsEnumerable());
        }
        public static TreeItemCollection CreateTree(IEnumerable<IChildItem> value)
        {
            var items = new TreeItemCollection();
            if (value != null)
            {
                var parentItems = (from o in value
                                   orderby o.DisplayPosition, o.Name
                                   select o).ToDictionaryCollection(o => o.ParentId ?? string.Empty, System.StringComparer.OrdinalIgnoreCase);
                using (var manager = new BusinessCollectionSettingsManager(items, BusinessCollectionSettings.CreateSettingsNone()))
                {
                    ProcessParent(parentItems, items, string.Empty);
                }
            }
            return items;
        }
        public static TreeItemCollection CreateTree(params IExtendedChildItem[] value)
        {
            return CreateTree(value.AsEnumerable(), string.Empty);
        }
        public static TreeItemCollection CreateTree(IEnumerable<IExtendedChildItem> value)
        {
            return CreateTree(value, string.Empty);
        }
        public static TreeItemCollection CreateTree(IEnumerable<IExtendedChildItem> value, string rootParentId)
        {
            var items = new TreeItemCollection();
            if (value != null)
            {
                var parentItems = (from o in value
                                   orderby o.DisplayPosition, o.Name
                                   select o).ToDictionaryCollection(o => o.ParentId ?? string.Empty, System.StringComparer.OrdinalIgnoreCase);
                using (var manager = new BusinessCollectionSettingsManager(items, BusinessCollectionSettings.CreateSettingsNone()))
                {
                    ProcessParent(parentItems, items, rootParentId);
                }
            }
            return items;
        }

        #endregion
        #region FindChildItems

        public static TreeItem[] FindChildItems(TreeItem item)
        {
            if (item == null)
                return null;
            var childItems = new List<TreeItem>();
            PrepareChildItems(childItems, item);
            return childItems.ToArray();
        }
        public static TreeItem[] FindChildItems(IEnumerable<TreeItem> items)
        {
            if (items == null)
                return null;
            var childItems = new List<TreeItem>();
            PrepareChildItems(childItems, items);
            return childItems.ToArray();
        }
        public static T[] FindChildItems<T>(IEnumerable<T> items, T rootItem, bool includeRootItem) where T : IChildItem
        {
            if (items == null)
                return null;
            var childItems = new List<T>();
            if (rootItem != null)
            {
                var parentIndex = (from o in items
                                   orderby o.DisplayPosition, o.Name
                                   select o).ToDictionaryCollection(o => o.ParentId ?? string.Empty, System.StringComparer.OrdinalIgnoreCase);
                PrepareChildItems(childItems, parentIndex, includeRootItem, rootItem);
            }
            return childItems.ToArray();
        }

        #endregion
        #region FindChildPath

        public static TreeItem[] FindChildPath(string childId, TreeItem item)
        {
            List<TreeItem> pathItems;

            pathItems = new List<TreeItem>();
            if (!string.IsNullOrWhiteSpace(childId))
                PrepareChildPath(pathItems, childId, item);

            return pathItems.ToArray();
        }
        public static TreeItem[] FindChildPath(string childId, IEnumerable<TreeItem> items)
        {
            List<TreeItem> pathItems;

            pathItems = new List<TreeItem>();
            if (!string.IsNullOrWhiteSpace(childId))
                PrepareChildPath(pathItems, childId, items);

            return pathItems.ToArray();
        }

        #endregion
        #region FindDataItems

        public static T[] FindDataItems<T>(TreeItem item)
        {
            if (item == null)
                return null;
            var dataItems = new List<T>();
            PrepareDataItems(dataItems, item);
            return dataItems.ToArray();
        }
        public static T[] FindDataItems<T>(IEnumerable<TreeItem> items)
        {
            if (items == null)
                return null;
            var dataItems = new List<T>();
            PrepareDataItems(dataItems, items);
            return dataItems.ToArray();
        }

        #endregion
        #region FindItem

        public static IParentItem FindItem(IEnumerable<IParentItem> items, string id)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(id))
                return null;
            foreach (var item in items)
            {
                if (item.Id.Equals(id, true, System.StringComparison.Ordinal))
                    return item;
                var tmp = FindItem(item.ChildItems, id);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }
        public static TreeItem FindItem(IEnumerable<TreeItem> items, string id)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(id))
                return null;
            foreach (var item in items)
            {
                if (item.Id.Equals(id, true, System.StringComparison.Ordinal))
                    return item;
                var tmp = FindItem(item.ChildItems, id);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }

        #endregion
        #region FindItemFromCode

        public static TreeItem FindItemFromCode(IEnumerable<TreeItem> items, string code)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(code))
                return null;
            foreach (var item in items)
            {
                if (item.Code.Equals(code, true, System.StringComparison.Ordinal))
                    return item;
                var tmp = FindItemFromCode(item.ChildItems, code);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }

        #endregion
        #region FindItemFromDataItemValue

        public static TreeItem FindItemFromDataItemValue(IEnumerable<TreeItem> items, object value, string propertyName)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(propertyName))
                return null;
            foreach (var item in items)
            {
                var dataItemValue = Sidvall.SystemContext.Current.CodeManager.GetPropertyValue(item.DataItem, propertyName);
                if (dataItemValue.Equals(value))
                    return item;
                var tmp = FindItemFromDataItemValue(item.ChildItems, value, propertyName);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }

        #endregion
        #region FindItems

        public static TreeItem[] FindItems(TreeItem item, IEnumerable<string> ids)
        {
            if (item == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareItems(dataItems, item, ids.ToHashSet(o => o, true));
            return dataItems.ToArray();
        }
        public static TreeItem[] FindItems(IEnumerable<TreeItem> items, IEnumerable<string> ids)
        {
            if (items == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareItems(dataItems, items, ids.ToHashSet(o => o, true));
            return dataItems.ToArray();
        }

        public static TreeItem[] FindItems(TreeItem item, System.Func<TreeItem, bool> includeItemHandler)
        {
            if (item == null)
                return null;
            var dataItems = new List<TreeItem>();
            if (includeItemHandler != null)
                PrepareItems(dataItems, item, includeItemHandler);
            return dataItems.ToArray();
        }
        public static TreeItem[] FindItems(IEnumerable<TreeItem> items, System.Func<TreeItem, bool> includeItemHandler)
        {
            if (items == null)
                return null;
            var dataItems = new List<TreeItem>();
            if (includeItemHandler != null)
                PrepareItems(dataItems, items, includeItemHandler);
            return dataItems.ToArray();
        }

        public static TreeItem[] FindItems(TreeItem item, bool? isEnabled, bool? isSelected, bool? isVisible, bool? hasDataItem, bool? hasChildItems)
        {
            if (item == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareItems(dataItems, item, isEnabled, isSelected, isVisible, hasDataItem, hasChildItems);
            return dataItems.ToArray();
        }
        public static TreeItem[] FindItems(IEnumerable<TreeItem> items, bool? isEnabled, bool? isSelected, bool? isVisible, bool? hasDataItem, bool? hasChildItems)
        {
            if (items == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareItems(dataItems, items, isEnabled, isSelected, isVisible, hasDataItem, hasChildItems);
            return dataItems.ToArray();
        }

        #endregion
        #region FindParent

        public static IParentItem FindParent(IEnumerable<IParentItem> items, string childId)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(childId))
                return null;
            foreach (var item in items)
            {
                if (item.ChildItems == null)
                    continue;
                var tmp = (from o in item.ChildItems
                           where o.Id.Equals(childId, true, System.StringComparison.Ordinal)
                           select o).FirstOrDefault();
                if (tmp != null)
                    return item;
                tmp = FindParent(item.ChildItems, childId);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }
        public static TreeItem FindParent(IEnumerable<TreeItem> items, string childId)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(childId))
                return null;
            foreach (var item in items)
            {
                var tmp = (from o in item.ChildItems
                           where o.Id.Equals(childId, true, System.StringComparison.Ordinal)
                           select o).FirstOrDefault();
                if (tmp != null)
                    return item;
                tmp = FindParent(item.ChildItems, childId);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }

        #endregion
        #region FindParentFromCode

        public static TreeItem FindParentFromCode(IEnumerable<TreeItem> items, string childCode)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(childCode))
                return null;
            foreach (var item in items)
            {
                var tmp = (from o in item.ChildItems
                           where o.Code.Equals(childCode, true, System.StringComparison.Ordinal)
                           select o).FirstOrDefault();
                if (tmp != null)
                    return item;
                tmp = FindParentFromCode(item.ChildItems, childCode);
                if (tmp != null)
                    return tmp;
            }
            return null;
        }

        #endregion
        #region FindParents

        public static TreeItem[] FindParents(TreeItem item, IEnumerable<string> childIds, bool includeAllParents)
        {
            if (item == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareParents(dataItems, item, childIds, includeAllParents);
            return dataItems.ToArray();
        }
        public static TreeItem[] FindParents(IEnumerable<TreeItem> items, IEnumerable<string> childIds, bool includeAllParents)
        {
            if (items == null)
                return null;
            var dataItems = new List<TreeItem>();
            PrepareParents(dataItems, items, childIds, includeAllParents);
            return dataItems.ToArray();
        }

        #endregion
        #region FindParentPath

        public static TreeItem[] FindParentPath(string parentId, IEnumerable<TreeItem> rootItems, TreeItem item)
        {
            List<TreeItem> pathItems;

            pathItems = new List<TreeItem>();
            PrepareParentPath(pathItems, parentId, rootItems, item);

            return pathItems.ToArray();
        }

        #endregion
        #region FindRoot

        public static TreeItem FindRoot(IEnumerable<TreeItem> rootItems, string childId)
        {
            if (rootItems == null)
                return null;
            if (rootItems.Count() == 1)
                return rootItems.First();
            if (string.IsNullOrWhiteSpace(childId))
                return null;
            foreach (var rootItem in rootItems)
            {
                if (rootItem.Id.Equals(childId, true, System.StringComparison.Ordinal))
                    return rootItem;
                var tmp = FindItem(rootItem.ChildItems, childId);
                if (tmp != null)
                    return rootItem;
            }
            return null;
        }

        #endregion
        #region FindRootPath

        public static TreeItem[] FindRootPath(IEnumerable<TreeItem> rootItems, TreeItem item)
        {
            var pathItems = new List<TreeItem>();
            PrepareParentPath(pathItems, null, rootItems, item);
            return pathItems.ToArray();
        }

        #endregion
        #region GetChildPath

        public static string GetChildPath(string childId, TreeItem item)
        {
            return GetChildPath(childId, item, DefaultNameSeparator);
        }
        public static string GetChildPath(string childId, TreeItem item, string separator)
        {
            TreeItem[] items;

            items = FindChildPath(childId, item);

            return Sidvall.Data.TreeManager.JoinToString(items, separator, false);
        }
        public static string GetChildPath(string childId, IEnumerable<TreeItem> items)
        {
            return GetChildPath(childId, items, DefaultNameSeparator);
        }
        public static string GetChildPath(string childId, IEnumerable<TreeItem> items, string separator)
        {
            items = FindChildPath(childId, items);

            return Sidvall.Data.TreeManager.JoinToString(items, separator, false);
        }

        #endregion
        #region GetRootPath

        public static string GetRootPath(TreeItem item, IEnumerable<TreeItem> rootItems)
        {
            return GetRootPath(item, rootItems, DefaultNameSeparator);
        }
        public static string GetRootPath(TreeItem item, IEnumerable<TreeItem> rootItems, string separator)
        {
            var treeItems = FindParentPath(null, rootItems, item);
            return Sidvall.Data.TreeManager.JoinToString(treeItems, separator, false);
        }

        #endregion
        #region GetName

        public static string GetName(TreeItem item, TreeItemNameType type)
        {
            if (item == null)
                return null;
            switch (type)
            {
                case TreeItemNameType.Name:
                    return item.Name;
                case TreeItemNameType.FullName:
                    return item.FullName;
                case TreeItemNameType.Code:
                    return item.Code;
                case TreeItemNameType.Id:
                    return item.Id;
                default:
                    throw new System.ArgumentException("Invalid type");
            }
        }

        #endregion
        #region InitializeItems

        public static void InitializeItems(IEnumerable<TreeItem> items, System.Action<TreeItem> initializeItemHandler)
        {
            InitializeItems(items, initializeItemHandler, true);
        }
        public static void InitializeItems(IEnumerable<TreeItem> items, System.Action<TreeItem> initializeItemHandler, bool processChildItems)
        {
            if (items == null)
                return;
            if (initializeItemHandler == null)
                return;
            foreach (var item in items)
            {
                initializeItemHandler(item);
                if (processChildItems)
                    InitializeItems(item.ChildItems, initializeItemHandler, processChildItems);
            }
        }

        #endregion
        #region IndexOf

        public static int? IndexOf(IEnumerable<IItem> items, string id)
        {
            if (items == null)
                return null;
            if (string.IsNullOrWhiteSpace(id))
                return null;

            int index = 0;
            foreach (var item in items)
            {
                if (item.Id == id)
                    return index;
                index += 1;
            }
            return null;
        }

        #endregion
        #region SetFullNames

        public static void SetFullNames(IEnumerable<TreeItem> items)
        {
            SetFullNames(items, items, null, DefaultNameSeparator, true, true, true);
        }
        public static void SetFullNames(IEnumerable<TreeItem> items, string separator)
        {
            SetFullNames(items, items, null, separator, true, true, true);
        }
        public static void SetFullNames(IEnumerable<TreeItem> items, string separator, bool processChildItems, bool raisePropertyChanged, bool updateState)
        {
            SetFullNames(items, items, null, separator, processChildItems, raisePropertyChanged, updateState);
        }

        #endregion
        #region SetSelectedBehavior

        public static void SetSelectedBehavior(IEnumerable<TreeItem> items, TreeItemSelectedBehavior selectedBehavior)
        {
            SetSelectedBehavior(items, selectedBehavior, true, true, true);
        }
        public static void SetSelectedBehavior(IEnumerable<TreeItem> items, TreeItemSelectedBehavior selectedBehavior, bool processChildItems, bool raisePropertyChanged, bool updateState)
        {
            if (items == null)
                return;
            foreach (var item in items)
            {
                item.SetSelectedBehavior(raisePropertyChanged, updateState, selectedBehavior);
                if (processChildItems)
                    SetSelectedBehavior(item.ChildItems, selectedBehavior, processChildItems, raisePropertyChanged, updateState);
            }
        }

        #endregion
        #region SetValues

        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible)
        {
            SetValues(items, isEnabled, isExpanded, isSelected, isSelectable, isVisible, true, true, true);
        }
        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible, IEnumerable<string> ids)
        {
            SetValues(items, isEnabled, isExpanded, isSelected, isSelectable, isVisible, true, true, true, ids);
        }
        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible, System.Func<TreeItem, bool> invertedValuesHandler)
        {
            SetValues(items, isEnabled, isExpanded, isSelected, isSelectable, isVisible, true, true, true, invertedValuesHandler);
        }

        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible, bool processChildItems, bool raisePropertyChanged, bool updateState)
        {
            if (items == null)
                return;
            foreach (var item in items)
            {
                item.SetValues(false, raisePropertyChanged, updateState, isEnabled, isExpanded, isSelected, isSelectable, isVisible);
                if (processChildItems)
                    SetValues(item.ChildItems, isEnabled, isExpanded, isSelected, isSelectable, isVisible, processChildItems, raisePropertyChanged, updateState);
            }
        }
        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible, bool processChildItems, bool raisePropertyChanged, bool updateState, IEnumerable<string> ids)
        {
            HashSet<string> index;

            if (items == null)
                return;
            if (ids != null)
                index = new HashSet<string>(ids);
            else
                index = new HashSet<string>();
            foreach (var item in items)
            {
                var invertedValues = ((string.IsNullOrWhiteSpace(item.Id)) || (!index.Contains(item.Id)));
                item.SetValues(invertedValues, raisePropertyChanged, updateState, isEnabled, isExpanded, isSelected, isSelectable, isVisible);
                if (processChildItems)
                    SetValues(item.ChildItems, isEnabled, isExpanded, isSelected, isSelectable, isVisible, processChildItems, raisePropertyChanged, updateState, ids);
            }
        }
        public static void SetValues(IEnumerable<TreeItem> items, bool? isEnabled, bool? isExpanded, bool? isSelected, bool? isSelectable,
            bool? isVisible, bool processChildItems, bool raisePropertyChanged, bool updateState, System.Func<TreeItem, bool> invertedValuesHandler)
        {
            if (items == null)
                return;
            foreach (var item in items)
            {
                var invertedValues = ((invertedValuesHandler != null) && (invertedValuesHandler(item)));
                item.SetValues(invertedValues, raisePropertyChanged, updateState, isEnabled, isExpanded, isSelected, isSelectable, isVisible);
                if (processChildItems)
                    SetValues(item.ChildItems, isEnabled, isExpanded, isSelected, isSelectable, isVisible, processChildItems, raisePropertyChanged, updateState, invertedValuesHandler);
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region PrepareChildItems

        private static void PrepareChildItems(List<TreeItem> dataItems, TreeItem item)
        {
            if (item == null)
                return;
            dataItems.Add(item);
            PrepareChildItems(dataItems, item.ChildItems);
        }
        private static void PrepareChildItems(List<TreeItem> dataItems, IEnumerable<TreeItem> items)
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareChildItems(dataItems, item);
        }
        private static void PrepareChildItems<T>(List<T> dataItems, Dictionary<string, System.Collections.ObjectModel.Collection<T>> parentIndex,
            bool includeItem, T item) where T : IChildItem
        {
            if (item == null)
                return;
            if (includeItem)
                dataItems.Add(item);
            if ((item.ParentId != null) && (parentIndex.ContainsKey(item.ParentId)))
            {
                var childItems = parentIndex[item.ParentId];
                PrepareChildItems(dataItems, parentIndex, true, childItems);
            }
        }
        private static void PrepareChildItems<T>(List<T> dataItems, Dictionary<string, System.Collections.ObjectModel.Collection<T>> parentIndex, 
            bool includeItems, IEnumerable<T> items) where T : IChildItem
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareChildItems(dataItems, parentIndex, includeItems, item);
        }

        #endregion
        #region PrepareDataItems

        private static void PrepareDataItems<T>(List<T> dataItems, TreeItem item)
        {
            if (item == null)
                return;
            if ((item.DataItem != null) && (item.DataItem is T))
                dataItems.Add((T)item.DataItem);
            PrepareDataItems(dataItems, item.ChildItems);
        }
        private static void PrepareDataItems<T>(List<T> dataItems, IEnumerable<TreeItem> items)
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareDataItems(dataItems, item);
        }

        #endregion
        #region PrepareItems

        private static void PrepareItems(List<TreeItem> dataItems, TreeItem item, HashSet<string> ids)
        {
            if (item == null)
                return;
            if ((ids != null) && (ids.Contains(item.Id, System.StringComparison.OrdinalIgnoreCase)))
                dataItems.Add(item);
            PrepareItems(dataItems, item.ChildItems, ids);
        }
        private static void PrepareItems(List<TreeItem> dataItems, IEnumerable<TreeItem> items, HashSet<string> ids)
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareItems(dataItems, item, ids);
        }

        private static void PrepareItems(List<TreeItem> dataItems, TreeItem item, System.Func<TreeItem, bool> includeItemHandler)
        {
            if (item == null)
                return;
            if (includeItemHandler(item))
                dataItems.Add(item);
            PrepareItems(dataItems, item.ChildItems, includeItemHandler);
        }
        private static void PrepareItems(List<TreeItem> dataItems, IEnumerable<TreeItem> items, System.Func<TreeItem, bool> includeItemHandler)
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareItems(dataItems, item, includeItemHandler);
        }

        private static void PrepareItems(List<TreeItem> dataItems, TreeItem item, bool? isEnabled, bool? isSelected, bool? isVisible, bool? hasDataItem, bool? hasChildItems)
        {
            if (item == null)
                return;
            if ((isEnabled == null) || (isEnabled.Value == item.IsEnabled))
            {
                if ((isSelected == null) || (isSelected.Value == item.IsSelected))
                {
                    if ((isVisible == null) || (isVisible.Value == item.IsVisible))
                    {
                        if ((hasDataItem == null) || (hasDataItem.Value == (item.DataItem != null)))
                        {
                            if ((hasChildItems == null) || (hasChildItems.Value == (item.ChildItems?.Count > 0)))
                            {
                                dataItems.Add(item);
                            }
                        }
                    }
                }
            }
            PrepareItems(dataItems, item.ChildItems, isEnabled, isSelected, isVisible, hasDataItem, hasChildItems);
        }
        private static void PrepareItems(List<TreeItem> dataItems, IEnumerable<TreeItem> items, bool? isEnabled, bool? isSelected, bool? isVisible, bool? hasDataItem, bool? hasChildItems)
        {
            if (items == null)
                return;
            foreach (var item in items)
                PrepareItems(dataItems, item, isEnabled, isSelected, isVisible, hasDataItem, hasChildItems);
        }

        #endregion
        #region PrepareChildPath

        private static bool PrepareChildPath(List<TreeItem> pathItems, string childId, IEnumerable<TreeItem> items)
        {
            if (items == null)
                return false;
            foreach (var item in items)
            {
                if (PrepareChildPath(pathItems, childId, item))
                    return true;
            }
            return false;
        }
        private static bool PrepareChildPath(List<TreeItem> pathItems, string childId, TreeItem item)
        {
            bool result;

            if (item.Id.Equals(childId, true, System.StringComparison.Ordinal))
                result = true;
            else
                result = PrepareChildPath(pathItems, childId, item.ChildItems);
            if (result)
                pathItems.Insert(0, item);
            return result;
        }

        #endregion
        #region PrepareParentPath

        private static void PrepareParentPath(List<TreeItem> pathItems, string parentId, IEnumerable<TreeItem> rootItems, TreeItem item)
        {
            pathItems.Insert(0, item);
            var parent = FindItem(rootItems, item.ParentId);
            if ((parent == null) || (parent.Id.Equals(parentId, true, System.StringComparison.Ordinal)))
                return;
            PrepareParentPath(pathItems, parentId, rootItems, parent);
        }

        #endregion
        #region PrepareParents

        private static bool PrepareParents(List<TreeItem> dataItems, TreeItem item, IEnumerable<string> childIds, bool includeAllParents)
        {
            if (item == null)
                return false;
            var foundChild = PrepareParents(dataItems, item.ChildItems, childIds, includeAllParents);
            var tmp = (from o in item.ChildItems
                       where childIds.Contains(o.Id, System.StringComparison.OrdinalIgnoreCase)
                       select o).FirstOrDefault();
            if ((tmp != null) || (includeAllParents && foundChild))
            {
                dataItems.Add(item);
                foundChild = true;
            }
            return foundChild;
        }
        private static bool PrepareParents(List<TreeItem> dataItems, IEnumerable<TreeItem> items, IEnumerable<string> childIds, bool includeAllParents)
        {
            if (items == null)
                return false;
            bool foundChild = false;
            foreach (var item in items)
            {
                if (PrepareParents(dataItems, item, childIds, includeAllParents))
                    foundChild = true;
            }
            return foundChild;
        }

        #endregion
        #region ProcessParent

        private static void ProcessParent(Dictionary<string, System.Collections.ObjectModel.Collection<IChildItem>> parentItems, TreeItemCollection items, string parentId)
        {
            System.Collections.ObjectModel.Collection<IChildItem> childItems;

            if (parentItems.TryGetValue(parentId, out childItems))
            {
                int iMax = childItems.Count;
                for (int i = 0; i < iMax; i++)
                {
                    var childItem = childItems[i];
                    string id = childItem.Id;
                    var item = TreeItem.CreateTreeItem(id, childItem.Name, childItem.ParentId, childItem.DisplayPosition, false, childItem);
                    items.Add(item);
                    if (!string.IsNullOrWhiteSpace(id))
                    {
                        using (var itemManager = new BusinessSettingsManager(item, BusinessSettings.CreateSettingsNone()))
                        {
                            using (var childManager = new BusinessCollectionSettingsManager(item.ChildItems, BusinessCollectionSettings.CreateSettingsNone()))
                            {
                                ProcessParent(parentItems, item.ChildItems, id);
                            }
                        }
                    }
                }
            }
        }
        private static void ProcessParent(Dictionary<string, System.Collections.ObjectModel.Collection<IExtendedChildItem>> parentItems, TreeItemCollection items, string parentId)
        {
            System.Collections.ObjectModel.Collection<IExtendedChildItem> childItems;

            if (parentItems.TryGetValue(parentId, out childItems))
            {
                int iMax = childItems.Count;
                for (int i = 0; i < iMax; i++)
                {
                    var childItem = childItems[i];
                    string id = childItem.Id;
                    var item = TreeItem.CreateTreeItem(id, childItem.Name, childItem.ParentId, childItem.DisplayPosition, false, childItem, childItem.GroupName, childItem.Code,
                        childItem.Description);
                    items.Add(item);
                    if (!string.IsNullOrWhiteSpace(id))
                    {
                        using (var itemManager = new BusinessSettingsManager(item, BusinessSettings.CreateSettingsNone()))
                        {
                            using (var childManager = new BusinessCollectionSettingsManager(item.ChildItems, BusinessCollectionSettings.CreateSettingsNone()))
                            {
                                ProcessParent(parentItems, item.ChildItems, id);
                            }
                        }
                    }
                }
            }
        }
        private static void ProcessParent(IEnumerable<IParentItem> parentItems, TreeItemCollection items, string parentId)
        {
            if (parentItems == null)
                return;
            int pos = 0;
            foreach (var parentItem in parentItems)
            {
                pos += 1;
                var item = TreeItem.CreateTreeItem(parentItem.Id, parentItem.Name, parentId, pos, false, parentItem);
                items.Add(item);
                using (var itemManager = new BusinessSettingsManager(item, BusinessSettings.CreateSettingsNone()))
                {
                    using (var childManager = new BusinessCollectionSettingsManager(item.ChildItems, BusinessCollectionSettings.CreateSettingsNone()))
                    {
                        ProcessParent(parentItem.ChildItems, item.ChildItems, item.Id);
                    }
                }
            }
        }

        #endregion
        #region SetFullNames

        private static void SetFullNames(IEnumerable<TreeItem> items, IEnumerable<TreeItem> rootItems, TreeItem parent, string separator, bool processChildItems, bool raisePropertyChanged, bool updateState)
        {
            string fullName;

            if (items == null)
                return;
            foreach (var item in items)
            {
                if ((parent != null) && (!string.IsNullOrWhiteSpace(parent.FullName)))
                    fullName = parent.FullName + separator + item.Name;
                else
                    fullName = GetRootPath(item, rootItems, separator);
                item.SetFullName(raisePropertyChanged, updateState, fullName);
                if (processChildItems)
                    SetFullNames(item.ChildItems, rootItems, item, separator, processChildItems, raisePropertyChanged, updateState);
            }
        }

        #endregion

        #endregion
    }
}
